/**
 * FloatingView - 可拖动的悬浮组件
 *
 * 功能特性：
 * - 悬浮在应用内容之上
 * - 支持拖动移动位置
 * - 自动边界检查，防止移出屏幕
 * - 支持自定义子组件
 * - 可配置初始位置
 * - 支持点击和长按事件
 * - 智能手势识别（点击、长按、拖动）
 * - 完整的 TypeScript 类型支持
 *
 * 使用场景：
 * - 音视频通话最小化窗口
 * - 悬浮按钮
 * - 悬浮工具栏
 */

import React, { useRef, useState, useCallback, useEffect } from 'react';
import {
  StyleSheet,
  Animated,
  PanResponder,
  Dimensions,
  LayoutChangeEvent,
  GestureResponderEvent,
  PanResponderGestureState,
} from 'react-native';

const { width: SCREEN_WIDTH, height: SCREEN_HEIGHT } = Dimensions.get('window');

// ==================== 类型定义 ====================

export interface FloatingViewProps {
  /** 子组件 */
  children: React.ReactNode;
  /** 初始 X 坐标，默认屏幕右侧 */
  initialX?: number;
  /** 初始 Y 坐标，默认屏幕中间偏上 */
  initialY?: number;
  /** 容器样式 */
  style?: object;
  /** 是否启用拖动，默认 true */
  draggable?: boolean;
  /** 点击回调 */
  onPress?: () => void;
  /** 长按回调 */
  onLongPress?: () => void;
  /** 长按触发时间（毫秒），默认 500 */
  longPressDuration?: number;
  /** 拖动开始回调 */
  onDragStart?: () => void;
  /** 拖动结束回调，返回最终位置 */
  onDragEnd?: (x: number, y: number) => void;
  /** 边距，组件距离屏幕边缘的最小距离，默认 10 */
  edgeMargin?: number;
  /** 是否启用自动贴边，默认 false */
  autoSnapToEdge?: boolean;
}

interface Position {
  x: number;
  y: number;
}

interface ComponentSize {
  width: number;
  height: number;
}

// ==================== 主组件 ====================

export const FloatingView: React.FC<FloatingViewProps> = ({
  children,
  initialX,
  initialY,
  style,
  draggable = true,
  onPress,
  onLongPress,
  longPressDuration = 500,
  onDragStart,
  onDragEnd,
  edgeMargin = 10,
  autoSnapToEdge = false,
}) => {
  // ==================== 状态管理 ====================

  // 组件尺寸
  const componentSizeRef = useRef<ComponentSize>({ width: 0, height: 0 });

  // 是否正在拖动
  const [isDragging, setIsDragging] = useState(false);

  // 动画位置值
  const position = useRef(
    new Animated.ValueXY({
      x: initialX !== undefined ? initialX : SCREEN_WIDTH - 80,
      y: initialY !== undefined ? initialY : SCREEN_HEIGHT / 3,
    }),
  ).current;

  const getPositionValue = useCallback((): Position => {
    return {
      // @ts-ignore
      x: position.x._value,
      // @ts-ignore
      y: position.y._value,
    };
  }, [position.x, position.y]);

  const getOffsetValue = useCallback((): Position => {
    return {
      // @ts-ignore
      x: position.x._offset,
      // @ts-ignore
      y: position.y._offset,
    };
  }, [position.x, position.y]);

  // 调试用：打印位置状态
  const logPositionState = (label: string) => {
    if (__DEV__) {
      const pos = getPositionValue();
      const offset = getOffsetValue();
      const total = {
        x: pos.x + offset.x,
        y: pos.y + offset.y,
      };
      console.log(
        `[FloatingView ${label}]`,
        'value:',
        { x: pos.x.toFixed(2), y: pos.y.toFixed(2) },
        'offset:',
        { x: offset.x.toFixed(2), y: offset.y.toFixed(2) },
        'total:',
        { x: total.x.toFixed(2), y: total.y.toFixed(2) },
      );
    }
  };

  // 记录拖动开始时的位置
  const dragStartPosition = useRef<Position>({ x: 0, y: 0 });

  // 记录点击开始的时间和位置，用于区分点击和拖动
  const gestureStartTime = useRef<number>(0);
  const gestureStartPos = useRef<Position>({ x: 0, y: 0 });

  // 长按定时器和标记
  const longPressTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
  const longPressTriggered = useRef<boolean>(false);

  // 动画执行标记
  const isAnimating = useRef<boolean>(false);

  // 标记是否已经设置过 offset（用于延迟设置 offset）
  const hasSetOffset = useRef<boolean>(false);

  // 记录上一次的总位置（用于检测真实跳变）
  const lastTotalPosition = useRef<Position>({ x: 0, y: 0 });

  // ==================== 位置监听 ====================

  useEffect(() => {
    // 初始化上一次的位置
    const currentPos = getPositionValue();
    const currentOffset = getOffsetValue();
    lastTotalPosition.current = {
      x: currentPos.x + currentOffset.x,
      y: currentPos.y + currentOffset.y,
    };

    // 监听 Y 轴位置变化
    const listenerId = position.y.addListener(event => {
      const offset = getOffsetValue();
      const newTotal = event.value + offset.y;

      // 计算与上一次记录位置的差值
      const deltaY = Math.abs(newTotal - lastTotalPosition.current.y);

      // 如果位置跳变超过 50px，记录警告（仅开发模式）
      if (__DEV__ && deltaY > 50 && !isAnimating.current && !isDragging) {
        console.warn('🔴 [FloatingView] 位置异常跳变！', {
          lastY: lastTotalPosition.current.y.toFixed(2),
          newY: newTotal.toFixed(2),
          delta: deltaY.toFixed(2),
        });
      }

      // 更新记录的位置
      lastTotalPosition.current.y = newTotal;
    });

    // 清理监听器
    return () => {
      position.y.removeListener(listenerId);
    };
  }, [getOffsetValue, getPositionValue, isDragging, position.y]);

  // ==================== 边界检查 ====================

  /**
   * 检查并修正位置，确保不超出屏幕边界
   */
  const validatePosition = useCallback(
    (pos: Position): Position => {
      const { width, height } = componentSizeRef.current;

      let newX = pos.x;
      let newY = pos.y;

      // X 轴边界检查
      const minX = edgeMargin;
      const maxX = SCREEN_WIDTH - width - edgeMargin;
      newX = Math.max(minX, Math.min(maxX, newX));

      // Y 轴边界检查
      const minY = edgeMargin;
      const maxY = SCREEN_HEIGHT - height - edgeMargin;
      newY = Math.max(minY, Math.min(maxY, newY));

      return { x: newX, y: newY };
    },
    [edgeMargin],
  );

  /**
   * 计算自动贴边位置（贴到左边或右边）
   */
  const getSnapToEdgePosition = useCallback(
    (pos: Position): Position => {
      const { width } = componentSizeRef.current;
      const centerX = pos.x + width / 2;

      // 判断靠近哪一边
      const snapToLeft = centerX < SCREEN_WIDTH / 2;

      return {
        x: snapToLeft ? edgeMargin : SCREEN_WIDTH - width - edgeMargin,
        y: pos.y, // Y 坐标保持不变
      };
    },
    [edgeMargin],
  );

  // ==================== 手势处理 ====================

  const clearLongPressTimer = () => {
    if (longPressTimer.current) {
      clearTimeout(longPressTimer.current);
      longPressTimer.current = null;
    }
  };

  const panResponder = useRef(
    PanResponder.create({
      onStartShouldSetPanResponder: () => draggable,
      onMoveShouldSetPanResponder: () => draggable,

      onPanResponderGrant: (
        evt: GestureResponderEvent,
        _: PanResponderGestureState,
      ) => {
        // 如果有动画正在执行，立即停止
        if (isAnimating.current) {
          if (__DEV__) {
            console.log('[FloatingView] 停止进行中的动画');
          }
          position.stopAnimation();
          isAnimating.current = false;
        }

        // 记录拖动开始的位置（获取当前的总位置）
        const currentOffset = getOffsetValue();
        const currentValue = getPositionValue();
        dragStartPosition.current = {
          x: currentValue.x + currentOffset.x,
          y: currentValue.y + currentOffset.y,
        };

        // 记录手势开始的时间和位置
        gestureStartTime.current = Date.now();
        gestureStartPos.current = {
          x: evt.nativeEvent.pageX,
          y: evt.nativeEvent.pageY,
        };

        // ⚠️ 关键：不在这里设置 offset，避免点击时闪动
        // 只记录初始状态，等到真正移动时再设置
        hasSetOffset.current = false;

        // 启动长按定时器
        longPressTriggered.current = false;
        clearLongPressTimer();
        if (onLongPress) {
          longPressTimer.current = setTimeout(() => {
            longPressTriggered.current = true;
            onLongPress();
          }, longPressDuration);
        }

        setIsDragging(true);
        onDragStart?.();
      },

      onPanResponderMove: (
        evt: GestureResponderEvent,
        gestureState: PanResponderGestureState,
      ) => {
        // 第一次移动时才设置 offset，避免点击时的闪动
        if (!hasSetOffset.current) {
          position.setOffset(dragStartPosition.current);
          position.setValue({ x: 0, y: 0 });
          hasSetOffset.current = true;
        }

        // 如果移动超过10px，取消长按
        if (Math.abs(gestureState.dx) > 10 || Math.abs(gestureState.dy) > 10) {
          clearLongPressTimer();
        }

        // 更新位置
        position.x.setValue(gestureState.dx);
        position.y.setValue(gestureState.dy);
      },

      onPanResponderRelease: (
        evt: GestureResponderEvent,
        gestureState: PanResponderGestureState,
      ) => {
        // 清除长按定时器
        clearLongPressTimer();

        logPositionState('RELEASE');

        // 只有设置过 offset 才需要 flatten
        if (hasSetOffset.current) {
          position.flattenOffset();
        }

        // 如果已触发长按，不执行其他逻辑
        if (longPressTriggered.current) {
          setIsDragging(false);
          return;
        }

        // 判断是点击还是拖动
        const gestureTime = Date.now() - gestureStartTime.current;
        const gestureDist = Math.sqrt(
          Math.pow(evt.nativeEvent.pageX - gestureStartPos.current.x, 2) +
            Math.pow(evt.nativeEvent.pageY - gestureStartPos.current.y, 2),
        );

        // 如果手势时间短且移动距离小，认为是点击
        const isClick = gestureTime < 200 && gestureDist < 10;

        if (isClick && onPress) {
          onPress();
          setIsDragging(false);
          return;
        }

        // 拖动：计算最终位置
        const finalX = dragStartPosition.current.x + gestureState.dx;
        const finalY = dragStartPosition.current.y + gestureState.dy;

        let targetPosition = validatePosition({ x: finalX, y: finalY });

        // 如果启用自动贴边，计算贴边位置
        if (autoSnapToEdge) {
          targetPosition = getSnapToEdgePosition(targetPosition);
        }

        // 动画到最终位置
        isAnimating.current = true;
        Animated.spring(position, {
          toValue: targetPosition,
          useNativeDriver: true,
          tension: 50,
          friction: 8,
        }).start(() => {
          isAnimating.current = false;
          setIsDragging(false);
          onDragEnd?.(targetPosition.x, targetPosition.y);
        });
      },

      onPanResponderTerminate: () => {
        if (__DEV__) {
          console.log('[FloatingView] 手势被中断');
        }

        // 手势被中断时，清理状态和定时器
        clearLongPressTimer();

        // 停止任何进行中的动画
        if (isAnimating.current) {
          position.stopAnimation();
          isAnimating.current = false;
        }

        // 只有设置过 offset 才需要 flatten
        if (hasSetOffset.current) {
          position.flattenOffset();
        }

        setIsDragging(false);
      },
    }),
  ).current;

  // ==================== 事件处理 ====================

  /**
   * 组件布局变化时，记录组件尺寸
   */
  const handleLayout = (event: LayoutChangeEvent) => {
    const { width, height } = event.nativeEvent.layout;
    componentSizeRef.current = { width, height };

    // 初次布局时，验证初始位置是否合法
    if (
      componentSizeRef.current.width === 0 &&
      componentSizeRef.current.height === 0
    ) {
      const currentPos = getPositionValue();
      const validatedPos = validatePosition(currentPos);

      // 如果位置不合法，立即设置到合法位置（无动画）
      if (currentPos.x !== validatedPos.x || currentPos.y !== validatedPos.y) {
        position.setValue(validatedPos);
      }
    }
  };

  // ==================== 渲染 ====================

  return (
    <Animated.View
      style={[
        styles.container,
        style,
        {
          transform: position.getTranslateTransform(),
          opacity: isDragging ? 0.8 : 1,
        },
      ]}
      onLayout={handleLayout}
      {...panResponder.panHandlers}
    >
      {children}
    </Animated.View>
  );
};

// ==================== 样式定义 ====================

const styles = StyleSheet.create({
  container: {
    position: 'absolute',
    // 默认阴影效果，让组件有悬浮感
    // iOS 阴影
    shadowColor: '#000',
    shadowOffset: {
      width: 0,
      height: 4,
    },
    shadowOpacity: 0.3,
    shadowRadius: 8,
    // Android 阴影
    elevation: 8,
  },
});
